package com.elvis.chat.utils.add;

import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

/**
 * Attachment provider.
 * @author Gaston Dombiak
 * @author Derek DeMoro
 */
public class AttachmentProvider implements IQProvider {

    private static final String PREFERRED_ENCODING = "UTF-8";

    public IQ parseIQ(XmlPullParser parser) throws Exception {
	final StringBuilder sb = new StringBuilder();
	try {
	    int event = parser.getEventType();
	    // get the content
	    while (true) {
		switch (event) {
		    case XmlPullParser.TEXT:
			// We must re-escape the xml so that the DOM won't throw an exception
			sb.append(StringUtils.escapeForXML(parser.getText()));
			break;
		    case XmlPullParser.START_TAG:
			sb.append('<').append(parser.getName()).append('>');
			break;
		    case XmlPullParser.END_TAG:
			sb.append("</").append(parser.getName()).append('>');
			break;
		    default:
		}

		if (event == XmlPullParser.END_TAG && AttachmentExtension.ELEMENT_NAME.equals(parser.getName()))
		    break;

		event = parser.next();
	    }
	} catch (XmlPullParserException e) {
	    e.printStackTrace();
	} catch (IOException e) {
	    e.printStackTrace();
	}

	String xmlText = sb.toString();
	return createAttachmentFromXML(xmlText);
    }

    /**
     * Builds a users Attachment from xml file.
     * @param xml the xml representing a Attachment.
     * @return the VCard.
     * @throws Exception if an exception occurs.
     */
    public static AttachmentInfo createAttachmentFromXML(String xml) throws Exception {
	AttachmentInfo vCard = new AttachmentInfo();

	DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
	DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
	Document document = documentBuilder.parse(new ByteArrayInputStream(xml.getBytes(PREFERRED_ENCODING)));

	new AttachmentReader(vCard, document).initializeFields();
	return vCard;
    }

    private static class AttachmentReader {

	private final AttachmentInfo Attachment;
	private final Document document;

	AttachmentReader(AttachmentInfo Attachment, Document document) {
	    this.Attachment = Attachment;
	    this.document = document;
	}

	public void initializeFields() {
	    Attachment.setFileName(getTagContents("FILENAME"));
	    Attachment.setFileSize(Long
		.parseLong(getTagContents("FILESIZE") == null ? "0" : getTagContents("FILESIZE")));
	    Attachment.setDescription(getTagContents("DESCRIPTION"));
	    Attachment.setMimeType(getTagContents("MIMETYPE"));
	    Attachment.setAudioLength(Long.parseLong(getTagContents("AUDIOLENGTH") == null ? "0"
		: getTagContents("AUDIOLENGTH")));
	    Attachment.setHashKey(getTagContents("HASHKEY"));
	    Attachment.setHashValue(getTagContents("HASHVALUE"));
	    Attachment.setBinval(getTagContents("BINVAL"));
	}

	private String getTagContents(String tag) {
	    NodeList nodes = document.getElementsByTagName(tag);
	    if (nodes != null && nodes.getLength() == 1) {
		return getTextContent(nodes.item(0));
	    }
	    return null;
	}

	private String getTextContent(Node node) {
	    StringBuilder result = new StringBuilder();
	    appendText(result, node);
	    return result.toString();
	}

	private void appendText(StringBuilder result, Node node) {
	    NodeList childNodes = node.getChildNodes();
	    for (int i = 0; i < childNodes.getLength(); i++) {
		Node nd = childNodes.item(i);
		String nodeValue = nd.getNodeValue();
		if (nodeValue != null) {
		    result.append(nodeValue);
		}
		appendText(result, nd);
	    }
	}
    }
}
